package com.dxy.shardingjdbc.keygenerator;

import cn.hutool.core.date.LocalDateTimeUtil;
import com.dxy.shardingjdbc.utils.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.shardingsphere.spi.keygen.ShardingKeyGenerator;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Properties;
import java.util.Set;

/**
 * @Description 自定义key生成器
 * @Author dangxianyue
 * @Date 2023/2/7 21:45
 */
@Slf4j
public class MyShardingKeyGenerator implements ShardingKeyGenerator {
    private static final String ID_KEY_PRE = "myid";
    private static final long MAX_SEQ_ONE_SEC = 9999999;
    private static Thread clearIdKeyThread = null;
    private static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyMMddHHmmss");
    private Properties properties = new Properties();

    static {
        clearIdKeyThread = new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    System.out.println("clear key thread run ...");
                    try {
                        if (RedisUtil.getRedisTemplate() != null) {
                            Set<String> keys = RedisUtil.scan(ID_KEY_PRE + "*");
                            String currentSecond = LocalDateTimeUtil.format(LocalDateTime.now(), formatter);
                            keys.forEach(key -> {
                                long keySecond = Long.parseLong(key.split(":")[1]);
                                if (Long.parseLong(currentSecond) > keySecond) {
                                    RedisUtil.delete(key);
                                }
                            });
                        }
                        // 10分钟执行一次，注意时钟不同步就可能会有重复的问题，或者再维护一个节点编号区别不同的服务实例
                        Thread.sleep(10*60*1000);
                    } catch (Exception e) {
                        log.error("clear key error: ", e);
                    }
                }
            }
        });
        clearIdKeyThread.setDaemon(true);
        clearIdKeyThread.setName("clear id key thread");
        clearIdKeyThread.start();
    }

    @Override
    public Comparable<?> generateKey() {
        return getId();
    }

    private Long getId() {
        Long id = null;
        String thisSecond = LocalDateTimeUtil.format(LocalDateTime.now(), formatter);
        Long seq = RedisUtil.incrBy(ID_KEY_PRE + ":" + thisSecond, 1);
        if (seq >= MAX_SEQ_ONE_SEC) {
            getId();
        } else {
            id = Long.parseLong(thisSecond + String.format("%06d", seq));
        }
        return id;
    }


    @Override
    public String getType() {
        return "MY_KEY_GENERATOR";
    }

    @Override
    public Properties getProperties() {
        return this.properties;
    }

    @Override
    public void setProperties(Properties properties) {
        this.properties = properties;
    }
}
